﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using MyPhotoIndex.Interfaces.Imaging;
using MyPhotoIndex.Utilities;
using System.IO;
using System.Threading;

namespace MyPhotoIndex.ImageBank
{
    public class LargeImageCache : ILargeImageProvider
    {
        private Dictionary<int, Image> m_cache = new Dictionary<int, Image>();
        private Queue<IImageData> m_imageQueue = new Queue<IImageData>();

        public Image GetLargeImage(IImageData imageData, Size requestedSize, List<IImageData> imageSortedList)
        {
            Image image = null;

            lock (m_cache)
            {
                if(m_cache.TryGetValue(imageData.Id, out image) == true)
                {
                    if (requestedSize == null ||
                        requestedSize == Size.Empty)
                    {
                        HandleNextImageCache(imageSortedList, imageData, requestedSize, 1);
                        return new Bitmap(image);
                    }

                    if(requestedSize.Width <= image.Width ||
                        requestedSize.Height <= image.Height)
                    {
                        HandleNextImageCache(imageSortedList, imageData, requestedSize, 1);
                        return new Bitmap(image);
                    }
                }
            }

            try
            {
                image = imageData.FormatProvider.LoadImage(imageData, requestedSize);
                lock (m_cache)
                {
                    if (m_imageQueue.Count == 8)
                    {
                        IImageData tempImageData = m_imageQueue.Dequeue();
                        Image tempImage = null;
                        if (m_cache.TryGetValue(tempImageData.Id, out tempImage) == true)
                        {
                            if (tempImage != null)
                            {
                                tempImage.Dispose();
                            }

                            m_cache.Remove(tempImageData.Id);
                        }
                    }

                    if (image != null)
                    {
                        imageData.LinkStatus = ImageLinkStatus.Valid;

                        m_cache[imageData.Id] = new Bitmap(image);
                        m_imageQueue.Enqueue(imageData);
                    }
                }
            }
            catch (DirectoryNotFoundException dex)
            {
                imageData.LinkStatus = ImageLinkStatus.Invalid;
                Logger.Log(dex);
            }
            catch (FileNotFoundException fex)
            {
                imageData.LinkStatus = ImageLinkStatus.Invalid;
                Logger.Log(fex);
            }
            catch (Exception ex)
            {
                imageData.LinkStatus = ImageLinkStatus.Invalid;
                Logger.Log(ex);
            }

            HandleNextImageCache(imageSortedList, imageData, requestedSize, 1);

            return image;
        }

        private void HandleNextImageCache(List<IImageData> imageSortedList, IImageData currentImageData, Size requestedSize, int numberOfImagesToCache)
        {
            return;

            if (imageSortedList == null)
            {
                return;
            }

            List<IImageData> imagesToLoad = new List<IImageData>();
            int listLength = imageSortedList.Count;
            for (int i = 0; i < listLength; i++)
            {
                IImageData imageData = imageSortedList[i];
                if (imageData == currentImageData)
                {
                    for (int images = i + 1, j = 0; (images < listLength) && (j < numberOfImagesToCache); images++, j++)
                    {
                        IImageData nextImageData = imageSortedList[images];
                        imagesToLoad.Add(nextImageData);
                    }

                    break;
                }
            }

            ImageLoadData imageLoadData = new ImageLoadData();
            imageLoadData.RequestedSize = requestedSize;
            imageLoadData.ImagesToLoad = imagesToLoad;
            ThreadPool.QueueUserWorkItem(new WaitCallback(LoadNextImages), imageLoadData);
        }

        private struct ImageLoadData
        {
            public List<IImageData> ImagesToLoad;
            public Size RequestedSize;
        }

        private void LoadNextImages(object state)
        {
            ImageLoadData imageLoadData = (ImageLoadData)state;

            List<IImageData> imagesToLoad = imageLoadData.ImagesToLoad;
            foreach (IImageData imagetoLoad in imagesToLoad)
            {
                using (Image image = GetLargeImage(imagetoLoad, imageLoadData.RequestedSize, null))
                {
                }
            }
        }

        public void Clear()
        {
            lock (m_cache)
            {
                foreach (Image image in m_cache.Values)
                {
                    image.Dispose();
                }

                m_cache.Clear();
                m_imageQueue.Clear();
            }
        }

        public void Remove(int imageId)
        {
            lock (m_cache)
            {
                Image image = null;
                if (m_cache.TryGetValue(imageId, out image) == true)
                {
                    if (image != null)
                    {
                        image.Dispose();
                    }

                    m_cache.Remove(imageId);
                }
            }
        }
    }
}
